EC2起動時に発生するキャパシティ不足の回避策とトレース方法についてまとめてみた
こんにちは、坂巻です。
EC2の作成や開始時に、以下のようなエラーに遭遇した事はありませんか?
We currently do not have sufficient t3.medium capacity in the Availability Zone you requested (ap-northeast-1a). Our system will be working on provisioning additional capacity. You can currently get t3.medium capacity by not specifying an Availability Zone in your request or choosing ap-northeast-1c, ap-northeast-1d.
こちらのエラーは、EC2をホストしているサーバのキャパシティが不足していることで、EC2の作成や起動に失敗し、その際に出力されるメッセージになります。今回は、そんなエラーが発生した際の、回避策やトレース方法についてまとめてみました。
回避策
キャパシティ不足が発生した際の回避策としては、以下の方法があります。
- 別のアベイラビリティゾーンで起動
- インスタンスタイプの変更
- オンデマンドキャパシティ予約の利用
別のアベイラビリティゾーンで起動
EC2の起動を試みたアベイラビリティゾーンとは、別のアベイラビリティゾーンで起動を行うことで解消されることがあります。 ap-northeast-1aで起動を試みた場合は、ap-northeast-1cで起動をする等の対応になります。
インスタンスタイプの変更
起動を試みたEC2のインスタンスタイプを変更することで、解消されることがあります。 t3.mediumで起動に失敗したら、m5.largeで起動してみる等の対応になります。
オンデマンドキャパシティ予約の利用
事前にキャパシティを確保しておくことで、キャパシティ不足の発生を未然に防ぐ対応となります。 詳細については、以下をご確認ください。
トレース方法
コンソール等から操作していれば、その場で気付く事ができますが、エンドユーザが操作をしていて、管理者側でも把握したい。そんな時に以下のような対応があげられます。
- CloudTrailのイベント履歴を確認する
- CloudWatch Logsに出力したイベントを確認する(要事前設定)
- Athenaより目的のイベントを検索して確認する(要事前設定)
CloudTrailのイベント履歴を確認する
キャパシティ不足のエラーが発生した際に、CloudTrailのイベント履歴から確認することができます。 確認方法は、CloudTrailのイベント履歴から「フィルター」に「イベント名」、値に「RunInstances」または、 「StartInstances」にて検索することで、エラーメッセージを含む履歴が確認できます。
キャパシティ不足が発生していた場合は、エラーコードにInsufficientInstanceCapacityが出力されます。
以下は「StartInstances」イベントにて、「InsufficientInstanceCapacity」が発生した際の画面例となります。
なお、CloudTrailコンソールでの履歴の保存期間は、90日となります。
CloudWatch Logsに出力したイベントを確認する
CloudWatch Logsに出力したイベントを確認するには、事前に設定が必要となります。CloudWatchルールにて、該当イベントを捕捉し、ルールのターゲットにLambda関数を設定します。Lambda関数でイベントを出力させることで、CloudWatch Logsに保存することが可能となります。
キャパシティ不足が発生した際は、イベントの「errorCode」に「Server.insufficientInstanceCapacity」が記録されます。
なお、CloudWatch Logsのログ保存期間は、1日〜10年、もしくは無期限の設定が可能です。 こちらは次項で、実際に設定してみたいと思います。
Athenaより目的のイベントを検索して確認する
Athenaにて出力したイベントを確認するには、事前に設定が必要となります。
CloudTrailの証跡を使用すると、S3バケットにCloudTrail実行履歴を保存することが可能になります。証跡には通常多数のイベントが記録されているので、目的のログを探すのは難しい場合があります。その際、S3バケットに保存された証跡の中から、目的のイベントを検索する手段として、Athenaを使用できます。証跡はS3バケットに保存されるので、削除しない限りログは残り続けます。
やってみた
上述しました「CloudWatch Logsに出力したイベントを確認する」を実際に設定してみたいと思います。Lambda関数とCloudWatchルールを作成します。
Lambda
Lambda起動時に受け取ったEventを出力する、関数を作成します。「RunInstances」、「StartInstances」について、それぞれサンプルを記載したいと思います。
RunInstances
「RunInstances」を補足するサンプルとなります。ランタイムはPython 3.6を使用しています。
import json def lambda_handler(event, context): event_time = event['time'] event_region = event['region'] event_instancetype = event['detail']['requestParameters']['instanceType'] event_errorcode = event['detail']['errorCode'] logdate = {"time": event_time , "region": event_region , "instanceType": event_instancetype,"errorCode": event_errorcode} print(logdate) return
上記はlambda_handlerが受け取ったイベントから、日時、アベイラビリティゾーン、インスタンスタイプ、エラーコードを出力しています。
StartInstances
「StartInstances」を補足するサンプルとなります。ランタイムはPython 3.6を使用しています。
import json def lambda_handler(event, context): event_time = event['time'] event_region = event['region'] event_instanceid = event['detail']['requestParameters']['instancesSet']['items'][0]['instanceId'] event_errorcode = event['detail']['errorCode'] logdate = {"time": event_time , "region": event_region , "instanceId": event_instanceid,"errorCode": event_errorcode} print(logdate) return
上記はlambda_handlerが受け取ったイベントから、日時、アベイラビリティゾーン、インスタンスID、エラーコードを出力しています。
Lambdaが受け取るイベントについては、該当イベントのCloudTrailにて詳細が確認できます。
なお、Lambdaのeventパラメータに対し、CloudTrailのJSONデータがそのままの渡されるのではなく、event内の「detail」キーの要素として設定されます。Lambdaに渡るEC2イベントについては、以下を参考にしてください。
CloudWatch
CloudWatchルールにイベントパターンを設定し、ターゲットに、作成したLambdaを設定します。
以下が、イベントパターンになります。
{ "detail-type": [ "AWS API Call via CloudTrail" ], "detail": { "eventSource": [ "ec2.amazonaws.com" ], "errorCode": [ "Server.InsufficientInstanceCapacity" ] } }
こちらの設定でキャパシティ不足が発生した際に、Lambdaが起動しCloudWatch Logsにログが出力されます。
動作確認
キャパシティ不足のイベントは任意に発生させることができないので、代替案で動作検証します。
RunInstances
RunInstancesの代替として、「InvalidParameterException」イベントを利用します。CloudWatchのイベントパターンに設定した「errorCode」を一時的に変更します。ハイライト部が変更箇所になります。(戻し忘れにご注意ください。)
{ "detail-type": [ "AWS API Call via CloudTrail" ], "detail": { "eventSource": [ "ec2.amazonaws.com" ], "errorCode": [ "Client.InvalidParameterValue" ] } }
以下のコマンドを実行すると、「InvalidParameterException」が発生します。こちらのコマンドは、存在しないインスタンスタイプを指定してEC2の起動を試みています。
$ aws ec2 run-instances --image-id ami-28ddc154 --instance-type t100.medium An error occurred (InvalidParameterValue) when calling the RunInstances operation: Invalid value 't100.medium' for InstanceType.
こちらを実行することで、更新したCloudWatchルールのパターンに合致し、Lambdaが起動されます。正しくLambdaが起動すると、CloudWatch Logsにロググループが作成されます。
詳細を確認すると、Lambdaで出力した内容がCloudWatch Logsに記録されています。
出力内容の確認ができたら、一時的に変更しました、CloudWatchルールのイベントパターンを元に戻してください。
StartInstances
こちらについても「RunInstances」同様、CloudWatchのイベントパターンを一時的に変更します。「errorCode」に「Client.InvalidInstanceID.Malformed」を指定します。
{ "detail-type": [ "AWS API Call via CloudTrail" ], "detail": { "eventSource": [ "ec2.amazonaws.com" ], "errorCode": [ "Client.InvalidInstanceID.Malformed" ] } }
以下のコマンドを実行すると、「InvalidInstanceID.Malformed」が発生します。こちらのコマンドは、存在しないインスタンスIDを指定してEC2の起動を試みています。
$ aws ec2 start-instances --instance-ids test An error occurred (InvalidInstanceID.Malformed) when calling the StartInstances operation: Invalid id: "test"
後続の動作については「RunInstances」に記載した内容と同一となります。こちらも、イベントパターンの戻し忘れにご注意ください。
さいごに
キャパシティ不足のイベントが発生した際に通知を行いたい場合は、上記設定に加え、該当Lambdaのメトリクスや、CloudWatch Logsのメトリクスフィルターを使用することで可能になります。キャパシティ不足を、管理者側でも確認したい!!そんな時に利用してみてはいかがでしょうか。